/***********************************************************************************

  Filename: usb_hid.c

  Description:  Application support for the HID class

***********************************************************************************/

/***********************************************************************************
* INCLUDES
*/
#include "simple_hid.h"
#include "hal_int.h"
#include "hal_mcu.h"

#include "usb_firmware_library_headers.h"
#include "usb_hid_reports.h"
#include "usb_class_requests.h"


/***********************************************************************************
* GLOBAL DATA
*/
KEYBOARD_IN_REPORT __data keyboard;
MOUSE_IN_REPORT __data mouse;


/** \brief Initializes the \ref module_usb_firmware_library_config module
*
* This function should be called first.
*/
void usbHidInit(void) {
  // Init USB library
  usbfwInit();

  // Initialize the USB interrupt handler with bit mask containing all processed USBIRQ events
  usbirqInit(0xFFFF);

  // Enable pullup on D+
  HAL_USB_PULLUP_ENABLE();

  // Enable global interrupts
  halIntOn();

} // usbHidInit

/// @}



void usbHidProcessEvents(void) {
  // Handle USB reset
  if (USBIRQ_GET_EVENT_MASK() & USBIRQ_EVENT_RESET) {
    USBIRQ_CLEAR_EVENTS(0xFFFF);
    usbfwResetHandler();
    USBPOW = USBPOW_SUSPEND_EN;
  }

  // Handle USB packets on EP0
  if (USBIRQ_GET_EVENT_MASK() & USBIRQ_EVENT_SETUP) {
    USBIRQ_CLEAR_EVENTS(USBIRQ_EVENT_SETUP);
    usbfwSetupHandler();
  }

  // Handle USB suspend
  if (USBIRQ_GET_EVENT_MASK() & USBIRQ_EVENT_SUSPEND) {
    USBIRQ_CLEAR_EVENTS(USBIRQ_EVENT_SUSPEND);  // Clear USB suspend interrupt
    usbsuspEnter();                             // Calling this function will take the chip into PM1 until a USB resume is deteceted.
    USBIRQ_CLEAR_EVENTS(USBIRQ_EVENT_RESUME);   // Clear USB resume interrupt.
  }
}


void usbHidProcessKeyboard(uint8 *pRfData) {
  uint8 i;

  keyboard.modifiers = pRfData[1];     // copy data from rx buffer.
  keyboard.reserved = pRfData[2];

  for (i = 0; i < sizeof(keyboard.pKeyCodes); i++) {
    keyboard.pKeyCodes[i] = pRfData[i + 3];
  }

  // Update and send the received HID keyboard report if USB endpoint is ready
  hidUpdateKeyboardInReport(&keyboard);

  if (hidSendKeyboardInReport()) {

    // For each successfully sent keyboard report, also clear the HID
    // keyboard report and send a blank report to release the key
    keyboard.modifiers = 0;
    keyboard.reserved = 0;

    for (i = 0; i < sizeof(keyboard.pKeyCodes); i++) {
      keyboard.pKeyCodes[i] = 0;
    }

    hidUpdateKeyboardInReport(&keyboard);

    for (i = 0; i < 100; i++) {
      if (hidSendKeyboardInReport())
        break;

      halMcuWaitMs(1);
    }
  }
}

void usbHidProcessMouse(uint8 *pRfData) {
  mouse.buttons = pRfData[1];         // copy data from rx buffer.

  if (mouse.buttons == 0) {
    mouse.dX = pRfData[2];
    mouse.dY = pRfData[3];
    mouse.dZ = pRfData[4];
  }

  // Update and send the received HID mouse report if USB endpoint is ready
  hidUpdateMouseInReport(&mouse);
  hidSendMouseInReport();
}
